--------------------------------------------------------------------------------------------------------
--  Freezer Gun v1                                                                                                         --
--------------------------------------------------------------------------------------------------------


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------                                                                      ADMINS, MODIFY VARIABLES HERE                                                             -----------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SWEP.Spawnable		= false
SWEP.AdminSpawnable	= true

SWEP.RateOfFire     = .7     -- pause between shots
SWEP.NPC            = true   -- works on NPC's
SWEP.PLY            = true   -- works on players
SWEP.Timed          = false  -- default mode, if false then sleep is permanent


//SWEP.ViewModel = "models/weapons/v_pistol.mdl"
//SWEP.WorldModel = "models/weapons/w_pistol.mdl"
SWEP.HoldType  = "pistol"


-- Basic SWEP Settings
SWEP.Purpose		= "Ragdoll Freeze Player"
SWEP.Instructions	= "Rate of Fire: " .. SWEP.RateOfFire .. " secs \nPrimary: Freeze\nSecondary: Unfreeze"

SWEP.Primary.ClipSize		= -1
SWEP.Primary.DefaultClip	= -1
SWEP.Primary.Automatic      = false
SWEP.Primary.Ammo			= "none"
SWEP.Secondary.ClipSize		= -1
SWEP.Secondary.DefaultClip	= -1
SWEP.Secondary.Automatic	= false
SWEP.Secondary.Ammo			= "none"

local ShootSound = Sound( "Weapon_Crossbow.Single" )
if SERVER then sleeping = {} end

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------                                                                      SWEP FUNCTIONS                                                                                            -----------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--  Make ply/npc sleep
function SWEP:PrimaryAttack()
	-- Fire the weapon
	self.Weapon:EmitSound(ShootSound)
	self.Weapon:SetNextPrimaryFire( CurTime() + self.RateOfFire )
	self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
	
	-- Only server handles ragdolls
	if(!SERVER) then return end
		
	local tr = self.Owner:GetEyeTrace()
	
	-- if there isn't anything there quit
	if ( tr.HitWorld ) then return end 
	
	-- tranq NPC/Player
	if tr.Entity:IsPlayer() and self.PLY then
			tranqPlayer(tr.Entity)

	elseif tr.Entity:IsNPC() and self.NPC then 
			tranqNPC(tr.Entity)
	end
	
end

-- Revive
function SWEP:SecondaryAttack( )
	-- Fire the weapon
	self.Weapon:EmitSound(ShootSound)
	self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
	
	-- Only server handles ragdolls
	if(!SERVER) then return end
	
	local tr = self.Owner:GetEyeTrace()
	
	-- if there isn't anything there quit
	if ( tr.HitWorld ) then return end 

	-- revive what you hit
	revive(tr.Entity)
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------                                                                      TRANQ FUNCTIONS                                                                                            ---------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------  Revive
function revive(ent)
	-- revive player
	if !ent then return end
	
	if ent.ply then
		local phy = ent:GetPhysicsObject()
		phy:EnableMotion(false)
		ent:SetSolid(SOLID_NONE)
		ent.ply:DrawViewModel(true)
		ent.ply:DrawWorldModel(true)
		ent.ply:Spawn()
		ent.ply:SetPos(ent:GetPos())
		ent.ply:SetVelocity(ent:GetPhysicsObject():GetVelocity())
	
	-- revive npc
	elseif ent.wasNPC then
		local npc = ents.Create(ent.npcType) -- create the entity
		
		util.PrecacheModel(ent:GetModel()) -- precache the model
		npc:SetModel(ent:GetModel()) -- and set it
		local spawnPos = ent:GetPos()+Vector(0,0,0) -- position to spawn it
		
		npc:SetPos(spawnPos) -- position
		npc:SetSkin(ent.npcSkin)
		npc:SetAngles(Angle(0,ent:GetAngles().y,0))
		
		if ent.npcWep != "" then -- if it's an NPC and we found a weapon for it when it was spawned, then
			npc:SetKeyValue("additionalequipment",ent.npcWep) -- give it the weapon
		end
		
		if ent.entType == "npc_citizen" then
			npc:SetKeyValue("citizentype",ent.npcCitType) -- set the citizen type - rebel, refugee, etc.
			if ent.npcCitType == "3" && ent.npcCitMed==1 then -- if it's a rebel, then it might be a medic, so check that
				npc:SetKeyValue("spawnflags","131072") -- set medic spawn flag
			end
		end
		
		npc:Spawn()
		npc:Activate()
		
	-- don't deal with other ents
	else 
		return
	end
	
	-- remove ragdoll
	ent:Remove()
end


-- Tranq NPC, mostly taken from crate maker
function tranqNPC(npc, t)
	-- get info about npc
	local skin = npc:GetSkin()
	local wep = ""
	local possibleWep = ents.FindInSphere(npc:GetPos(),0.01) -- find anything in the center basically
	for k, v in pairs(possibleWep) do 
		if string.find(v:GetClass(),"weapon_") == 1 then 
			wep = v:GetClass()
		end
	end

	local citType = "" -- citizen type
	local citMed = 0 -- is it a medic? assume no
	if npc:GetClass() == "npc_citizen" then
		citType = string.sub(npc:GetModel(),21,21) -- get group number (e.g. models/humans/group0#/whatever)
		if string.sub(npc:GetModel(),22,22) == "m" then citMed = 1 end -- medic skins have an "m" after the number
	end

	-- make ragdoll now that all info is gathered	
	local rag = ents.Create( "prop_ragdoll" )
    if not rag:IsValid() then return end
	
	-- build rag
	rag:SetModel( npc:GetModel() )
    rag:SetKeyValue( "origin", npc:GetPos().x .. " " .. npc:GetPos().y .. " " .. npc:GetPos().z )
	rag:SetAngles(npc:GetAngles())
	rag:SetColor(150,255,255,255)
	
	-- npc vars
	rag.wasNPC = true
	rag.npcType = npc:GetClass()
	rag.npcWep = wep
	rag.npcCitType = citType
	rag.npcCitMed = citMed
	rag.npcSkin = skin
	
	--finalize
	rag:Spawn()
    rag:Activate()
	
	-- make ragdoll fall
	//rag:GetPhysicsObject():SetVelocity(8*npc:GetVelocity())
	
	--remove npc
	npc:Remove()

	timer.Create("time",0.2,1, function()

	// If it already has a StatueInfo table then it's already statued
	if ( rag:GetTable().StatueInfo != nil )  then return false end

	rag:GetTable().StatueInfo = {}
	rag:GetTable().StatueInfo.Welds = {}

	local bones = rag:GetPhysicsObjectCount()

	local forcelimit = 0

	// Weld each physics object together
	for bone=1, bones do
	
		local bone1 = bone - 1
		local bone2 = bones - bone
		
		// Don't do identical two welds
		if ( !rag:GetTable().StatueInfo.Welds[bone2] ) then
		
			local constraint1 = constraint.Weld( rag, rag, bone1, bone2, forcelimit )
			
			if ( constraint1 ) then
			
				rag:GetTable().StatueInfo.Welds[bone1] = constraint1
				//self:GetOwner():AddCleanup( "constraints", constraint1 )
			
			end
			
		end
		
		local constraint2 = constraint.Weld( rag, rag, bone1, 0, forcelimit )
		
		if ( constraint2 ) then
		
			rag:GetTable().StatueInfo.Welds[bone1+bones] = constraint2
			//self:GetOwner():AddCleanup( "constraints", constraint2 )
		
		end
		
		local effectdata = EffectData()
			 effectdata:SetOrigin( rag:GetPhysicsObjectNum( bone1 ):GetPos() )
			 effectdata:SetScale( 1 )
			 effectdata:SetMagnitude( 1 )
		util.Effect( "GlassImpact", effectdata, true, true )
		
	end

	end )

	return rag

end

-- Tranq a player, taken from ragdoll gun
function tranqPlayer(ply, t)
	-- create ragdoll
	local rag = ents.Create( "prop_ragdoll" )
    if not rag:IsValid() then return end

	-- build rag
	rag:SetModel( ply:GetModel() )
    rag:SetKeyValue( "origin", ply:GetPos().x .. " " .. ply:GetPos().y .. " " .. ply:GetPos().z )
	rag:SetAngles(ply:GetAngles())
	rag:SetColor(150,255,255,255)
			
	-- player vars
	rag.ply = ply
	
	-- "remove" player
	ply:StripWeapons()
	ply:DrawViewModel(false)
	ply:DrawWorldModel(false)
	ply:Spectate(OBS_MODE_CHASE)
	ply:SpectateEntity(rag)
	
	-- finalize ragdoll
    rag:Spawn()
    rag:Activate()
	
	-- make ragdoll fall
	rag:GetPhysicsObject():SetVelocity(4*ply:GetVelocity())
	
	timer.Create("time",0.2,1, function()

	// If it already has a StatueInfo table then it's already statued
	if ( rag:GetTable().StatueInfo != nil )  then return false end

	rag:GetTable().StatueInfo = {}
	rag:GetTable().StatueInfo.Welds = {}

	local bones = rag:GetPhysicsObjectCount()

	local forcelimit = 0

	// Weld each physics object together
	for bone=1, bones do
	
		local bone1 = bone - 1
		local bone2 = bones - bone
		
		// Don't do identical two welds
		if ( !rag:GetTable().StatueInfo.Welds[bone2] ) then
		
			local constraint1 = constraint.Weld( rag, rag, bone1, bone2, forcelimit )
			
			if ( constraint1 ) then
			
				rag:GetTable().StatueInfo.Welds[bone1] = constraint1
				//self:GetOwner():AddCleanup( "constraints", constraint1 )
			
			end
			
		end
		
		local constraint2 = constraint.Weld( rag, rag, bone1, 0, forcelimit )
		
		if ( constraint2 ) then
		
			rag:GetTable().StatueInfo.Welds[bone1+bones] = constraint2
			//self:GetOwner():AddCleanup( "constraints", constraint2 )
		
		end
		
		local effectdata = EffectData()
			 effectdata:SetOrigin( rag:GetPhysicsObjectNum( bone1 ):GetPos() )
			 effectdata:SetScale( 1 )
			 effectdata:SetMagnitude( 1 )
		util.Effect( "GlassImpact", effectdata, true, true )
		
	end

	end )


	return rag

end

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------                                                                      CONSOLE FUNCTIONS                                                                                        ---------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

-- store the console player in
local plyent = nil

--- apply tranq to self
function tranqSelf(ply, cmd, args)
	if !plyent then	plyent = tranqPlayer(ply, args[1]) end
end

-- revive self
function reviveSelf()
	revive(plyent)
	plyent=nil
end

concommand.Add( "tranq_self", tranqSelf) 
concommand.Add( "revive_self", reviveSelf) 

hook.Add("Think", "checksleeping", checkSleeping)
